package com.fp;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 */
public class SpringBootGenerator {
    
    private static String template_root_dir_path = "template";

    private static String template_java_code_dir_path = "$java-code";

    private static String template_java_code_test_dir_path = "$java-code-test";

    private static String template_java_resources_dir_path = "$java-resources";

    private static File template_root_dir = new File(template_root_dir_path);

    private static File template_java_code_dir = new File(template_root_dir, template_java_code_dir_path);

    private static File template_java_code_test_dir = new File(template_root_dir, template_java_code_test_dir_path);

    private static File template_java_resources_dir = new File(template_root_dir, template_java_resources_dir_path);

    private static Pattern pattern = Pattern.compile("(\\$\\{.*?\\})");

    private String upFirstName(String name) {
        char[] cs = name.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }

    private JSONObject loadTemplateJson(String template_json_path) throws Exception {
        BufferedReader br = new BufferedReader(new FileReader(new File(template_json_path)));
        StringBuilder jsonBuilder = new StringBuilder();

        String line;
        while ((line = br.readLine()) != null) {
            jsonBuilder.append(line);
        }

        return JSONObject.parseObject(jsonBuilder.toString());
    }

    private String recurse_get(JSONObject templateJson, String key) {
        if (templateJson.containsKey(key)) {
            String ret = templateJson.getString(key);
            return ret;
        } else {
            String ret = null;
            for (Map.Entry e : templateJson.entrySet()) {
                if (e.getValue() instanceof JSONObject) {
                    ret = recurse_get((JSONObject) e.getValue(), key);
                    if (ret != null) {
                        break;
                    }
                }
            }
            return ret;
        }
    }

    private void createCodeDir(String appName, String packageName, File outputDir) {
        String packagePath = packageName.replaceAll("\\.", "/");

        File src_java = new File(outputDir, appName + "/src/main/java/" + packagePath);
        File src_resource = new File(outputDir, appName + "/src/main/resources");
        File src_test = new File(outputDir, appName + "/src/test/java/" + packagePath);

        if (!outputDir.exists())
            outputDir.mkdirs();
        if (!src_java.exists())
            src_java.mkdirs();
        if (!src_resource.exists())
            src_resource.mkdirs();
        if (!src_test.exists())
            src_test.mkdirs();
    }

    private void copyCode(String appName, String packageName, File outputDir) throws Exception {
        String packagePath = packageName.replaceAll("\\.", "/");

        File root = new File(outputDir, appName);
        File src_java = new File(outputDir, appName + "/src/main/java/" + packagePath);
        File src_resource = new File(outputDir, appName + "/src/main/resources");
        File src_test = new File(outputDir, appName + "/src/test/java/" + packagePath);

        recurse_copy_all(template_root_dir, root);
        recurse_copy_all(template_java_code_dir, src_java);
        recurse_copy_all(template_java_code_test_dir, src_test);
        recurse_copy_all(template_java_resources_dir, src_resource);
    }

    private void recurse_copy_all(File src, File destDir) throws Exception {
        if (!src.isDirectory()) {
            copyFile(src, destDir);
        } else {
            if(src.getName().equals(template_root_dir.getName())) {
                File[] subFiles = src.listFiles();
                for (File subFile : subFiles) {
                    if(!subFile.isDirectory())
                        copyFile(subFile, destDir);
                }
            }else {
                File src2 = new File(destDir, src.getName());
                if (!src2.exists() && !src.getName().startsWith("$")) {
                    src2.mkdirs();
                }

                if (!src.getName().startsWith("$")) {
                    destDir = new File(destDir, src2.getName());
                }


                File[] subFiles = src.listFiles();
                for (File subFile : subFiles) {
                    recurse_copy_all(subFile, destDir);
                }
            }
        }
    }

    private void copyFile(File src, File destDir) throws IOException {
        FileInputStream in = new FileInputStream(src);
        FileOutputStream out = new FileOutputStream(new File(destDir, src.getName()));

        IOUtils.copy(in, out);

        out.close();
        in.close();
    }

    private void recurse_replace_content(File replaceFile, JSONObject templateJson, List<File> templateFile) throws Exception {

        if (replaceFile.isDirectory()) {
            File subFiles[] = replaceFile.listFiles();
            for (File subFile : subFiles) {
                recurse_replace_content(subFile, templateJson, templateFile);
            }
        } else {

            //替换文件内容
            BufferedReader br = new BufferedReader(new FileReader(replaceFile));

            List<String> fileContents = new ArrayList<>();

            String line;

            while((line = br.readLine()) != null) {
                Matcher matcher = pattern.matcher(line);
                if(matcher.find()) {
                    int groupCount = matcher.groupCount();
                    while(groupCount > 0) {
                        String matchedStr = matcher.group(groupCount);
                        String key = matchedStr.substring(2, matchedStr.length() - 1);
                        if(key.equals("appName")) {
                            line = line.replace(matchedStr, upFirstName(recurse_get(templateJson, key)));
                        }else{
                            String val =  recurse_get(templateJson, key);
                            if(val == null) {
                                throw new IllegalArgumentException("未配置变量"+ key);
                            }
                            line = line.replace(matchedStr, val);
                        }
                        groupCount --;
                    }
                }
                fileContents.add(line);
            }

            BufferedWriter bw = new BufferedWriter(new FileWriter(replaceFile));
            for(String content : fileContents) {
                bw.write(content);
                bw.newLine();
            }

            bw.close();
            br.close();

            //文件名变量替换
            String fileName = replaceFile.getName();
            Matcher matcher = pattern.matcher(fileName);
            if (matcher.find()) {

                int groupCount = matcher.groupCount();
                String newFileName = new String();
                while(groupCount > 0) {

                    String matchedStr = matcher.group(groupCount);
                    String key = matchedStr.substring(2, matchedStr.length() - 1);
                    String val = recurse_get(templateJson, key);
                    if(val == null) {
                        throw new IllegalArgumentException("未配置变量"+ key);
                    }
                    if(matcher.start() == 0) {
                        val = upFirstName(val);
                    }

                    newFileName = fileName.replace(matchedStr, val);
                    fileName = newFileName;

                    groupCount --;
                }

                FileInputStream in = new FileInputStream(replaceFile);
                FileOutputStream out = new FileOutputStream(new File(replaceFile.getParent() + IOUtils.DIR_SEPARATOR + newFileName));
                IOUtils.copy(in, out);

                out.close();
                in.close();

                templateFile.add(replaceFile);
            }
        }
    }

    public void generate(String outputPath, String templateJsonPath) throws Exception {
        //输出路径
        File outputDir = new File(outputPath);

        //加载json变量文件
        JSONObject templateJson = loadTemplateJson(templateJsonPath);

        //应用名称
        String appName = recurse_get(templateJson,"appName");
        if(appName == null) {
            throw new IllegalArgumentException("未配置变量appName");
        }

        //包名
        String packageName = recurse_get(templateJson,"packageName");
        if(packageName == null) {
            throw new IllegalArgumentException("未配置变量packageName");
        }

        //创建项目结构
        createCodeDir(
                appName,
                packageName,
                outputDir);

        //复制模版代码
        copyCode(
                appName,
                packageName,
                outputDir);

        //模版变量替换
        List<File> templateFiles = new ArrayList<>();
        recurse_replace_content(new File(outputDir, appName), templateJson, templateFiles);
        for(File file : templateFiles) {
            file.delete();
        }
    }

    public static void main(String[] args) throws Exception {
        SpringBootGenerator springBootGenerator = new SpringBootGenerator();
        springBootGenerator.generate("temp", "template.json");
    }

}
